package com.veskogeorgiev.farm;

import java.awt.AWTException;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Farm {

	Point acceptPos = new Point(457, 612);
	static final Point POINTER = new Point(791, 723);
	static final Point POINTER_MENU = new Point(798, 654);

	static final Point[] COW = { new Point(12, 5), new Point(25, 12),
			new Point(38, 18), new Point() };
	static final Point[] LAND = { new Point(25, 12), new Point(50, 25),
			new Point(75, 36), new Point() };
	static final Point[] BALE = { new Point(7, 3), new Point(12, 6),
			new Point(19, 9), new Point() };
	static final Point[] TREE = { new Point(7, 3), new Point(12, 6),
			new Point(19, 9), new Point() };
	static final Point[] SWAN = { new Point(7, 3), new Point(12, 6),
			new Point(19, 9), new Point() };
	static final Point[] SHEEP = { new Point(7, 3), new Point(12, 6),
			new Point(19, 9), new Point() };
	static final Point[] CHICKEN = { new Point(7, 3), new Point(12, 6),
			new Point(19, 9), new Point() };

	static final int START_TIMEOUT = 10;

	static final Point SELLMENU = new Point(10, 37);
	static final Point COLLECTMENU = new Point(10, 60);

	private Robot r;
	private Point start;
	private int x, y;

	int total;
	int processed;
	int zoom = 0;
	int delay = 100;
	boolean cancel = false;

	public Farm() throws AWTException {
		r = new Robot();
		r.setAutoDelay(0);
		setStart();
	}

	private void setStart() {
		PointerInfo info = MouseInfo.getPointerInfo();
		start = info.getLocation();
		x = start.x;
		y = start.y;
	}

	private void move(int x, int y) {
		r.mouseMove(x, y);
	}

	private void press() {
		r.mousePress(InputEvent.BUTTON1_MASK);
	}

	private void release() {
		r.mouseRelease(InputEvent.BUTTON1_MASK);
	}

	private void set(int x, int y) {
		this.x = x;
		this.y = y;
		move(x, y);
	}

	public static void sleep(int ms) {
		try {
			Thread.sleep(ms);
		} catch (InterruptedException e) {
		}
	}

	private boolean click() {
		sleep(delay);
		if(cancel) return true;
		press();
		release();
		sleep(delay);
		return false;
	}

	private void transXY(int dx, int dy) {
		int xadd = dx / Math.abs(dx);
		int yadd = dy / Math.abs(dy);
		for (int j = 0; j < Math.max(Math.abs(dx), Math.abs(dy)); j++) {
			if (j < Math.abs(dx))
				x += xadd;
			if (j < Math.abs(dy))
				y += yadd;
			move(x, y);
		}
	}

	private boolean popupMenuClick(Point coords) {
		transXY(coords.x, coords.y);
		return click();
	}

	private boolean dialogButtonClick(Point coords) {
		set(coords.x, coords.y);
		sleep(500);
		boolean result = click();
		sleep(500);
		return result;
	}

	private void singleClick(int rows, int cols, Point item) {
		if (item == null)
			return;
		for (int i = 0; i < rows; i++) {
			set(start.x + i * item.x, start.y + i * item.y);
			for (int j = 0; j < cols; j++) {
				if(click()) return;
				transXY(item.x, -item.y);
				processed++;
			}
		}
	}

	private void trippleClick(int rows, int cols, Point item,
			Point firstObject, Point secondObject) {
		for (int i = 0; i < rows; i++) {
			set(start.x + i * item.x, start.y + i * item.y);
			for (int j = 0; j < cols; j++) {
				if(click()) return;
				int sx = x;
				int sy = y;

				popupMenuClick(firstObject);
				dialogButtonClick(secondObject);

				set(sx, sy);
				transXY(item.x, -item.y);
				processed++;
			}
		}
	}

	private void doubleClick(int rows, int cols, Point item, Point firstObject) {
		doubleClick(rows, cols, item, firstObject, false);
	}

	private void doubleClick(int rows, int cols, Point item, Point firstObject,
			boolean hasDialog) {
		if (item == null || firstObject == null)
			return;
		for (int i = 0; i < rows; i++) {
			set(start.x + i * item.x, start.y + i * item.y);
			for (int j = 0; j < cols; j++) {
				if(click()) return;
				int sx = x;
				int sy = y;

				if (hasDialog)
					dialogButtonClick(firstObject);
				else
					popupMenuClick(firstObject);

				set(sx, sy);
				transXY(item.x, -item.y);
				processed++;
			}
		}
	}

	public void work(Object... args) throws IllegalArgumentException,
			SecurityException, IllegalAccessException, NoSuchFieldException,
			NoSuchMethodException, InvocationTargetException {
		Point item = ((Point[]) this.getClass().getDeclaredField(
				((String) args[0]).toUpperCase()).get(null))[zoom];
		String action = ((String) args[1]).toLowerCase();
		int rows = (Integer) args[2];
		int cols = (Integer) args[3];
		Method m = this.getClass().getMethod(action,
				new Class[] { int.class, int.class, Point.class });
		setStart();
		m.invoke(this, new Object[] { rows, cols, item });
	}

	public void seed(int rows, int cols, Point item) {
		singleClick(rows, cols, item);
	}

	public void plow(int rows, int cols, Point item) {
		singleClick(rows, cols, item);
	}

	public void harvest(int rows, int cols, Point item) {
		singleClick(rows, cols, item);
	}

	public void sell(int rows, int cols, Point item) {
		trippleClick(rows, cols, item, SELLMENU, acceptPos);
	}

	public void put(int rows, int cols, Point item) {
		singleClick(rows, cols, item);
	}

	public void collect(int rows, int cols, Point item) {
		doubleClick(rows, cols, item, COLLECTMENU);
	}

	public void clean(int rows, int cols, Point item) {
		doubleClick(rows, cols, item, acceptPos, true);
	}
}